package org.ly.uap.client.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;

public final class ReflectUtils {
    public static <T> Class<T> loadClass(String className)
            throws IllegalArgumentException {
        try {
            return (Class<T>)Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException(className + " class not found.");
        }

    }

    public static <T> T newInstance(String className, Object[] args) {
        return newInstance(loadClass(className), args);
    }

    public static <T> T newInstance(Class<T> clazz, Object[] args) {
        Class[] argClasses = new Class[args.length];
        for (int i = 0; i < args.length; i++)
            argClasses[i] = args[i].getClass();
        try {
            return clazz.getConstructor(argClasses).newInstance(args);
        } catch (Exception e) {
            throw new IllegalArgumentException("Error creating new instance of " + clazz, e);
        }

    }

    public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) {
        try {
            return getPropertyDescriptor(Introspector.getBeanInfo(clazz), propertyName);
        } catch (IntrospectionException e) {
            throw new RuntimeException("Failed getting bean info for " + clazz, e);
        }

    }

    public static PropertyDescriptor getPropertyDescriptor(BeanInfo info, String propertyName) {
        for (int i = 0; i < info.getPropertyDescriptors().length; i++) {
            PropertyDescriptor pd = info.getPropertyDescriptors()[i];
            if (pd.getName().equals(propertyName)) {
                return pd;
            }
        }
        return null;
    }

    public static void setProperty(String propertyName, Object value, Object target) {
        try {
            setProperty(propertyName, value, target, Introspector.getBeanInfo(target.getClass()));
        } catch (IntrospectionException e) {
            throw new RuntimeException("Failed getting bean info on target JavaBean " + target, e);
        }
    }

    public static void setProperty(String propertyName, Object value, Object target, BeanInfo info) {
        try {
            PropertyDescriptor pd = getPropertyDescriptor(info, propertyName);
            pd.getWriteMethod().invoke(target, new Object[]{value});
        } catch (InvocationTargetException e) {
            throw new RuntimeException("Error setting property " + propertyName, e.getCause());
        } catch (Exception e) {
            throw new RuntimeException("Error setting property " + propertyName, e);
        }
    }
}
